import 'package:flutter/material.dart';
import 'package:kq_flutter_core_widget/utils/kq_screen_util.dart';
import 'package:get/get.dart';
import '../../resources/kq_theme_colors.dart';
import 'package:kq_flutter_core_widget/widgets/sliver/sliver_header.dart';

class ListService extends GetxController {
  late int nowSection = 0;
  late double maxSectionHeight = 0;
  late int didSection = 0;
}

class KqSectionListView<E> extends StatefulWidget {
  ///分区数
  final int section;

  ///是否显示索引,默认false,若要显示索引且无需自定义时，可让参数对象类集成KqSectionIndexModel，并使用KqSectionIndexState中方法获取分区对象
  final bool isShowIndex;

  ///行高是否相同默认false
  final bool isSameHeight;

  ///分区头部是否吸
  final bool isFixTop;

  ///分区高度,吸顶时才会被使用，不传为自适应，传了表示固定死高度
  final double? sectionHeight;

  ///索引列表
  final List? indexList;

  ///单个索引的高度的最大高度,默认为16
  final double? indexHeight;

  ///索引区间宽度，默认为16
  final double? indexWidth;

  /*索引区间的最大长度,不设置则索引区间为sectionView的高度，每个索引高度为indexHeight，
  设置后每个索引的最大高度indexHeight，超屏后每个高度会自动缩放*/
  final double? indexListHeight;

  ///索引文字大小，默认为12
  final double? indexFont;

  ///索引文字颜色，默认为8C8C8C
  final Color indexTextColor;

  ///行高isSameHeight=true时设置才会被使用，默认为36
  final double Function(int section)? rowHeight;

  ///对应section分区内的内容数组
  final List<E> Function(int section) itemList;

  ///列表头部UI
  final Widget? Function()? listHeaderBuilder;

  ///列表尾部UI
  final Widget? Function()? listFooterBuilder;

  ///分组头部UI
  final Widget Function(int section) headerBuilder;

  ///分组尾部UI
  final Widget? Function(int section)? footerBuilder;

  ///cell的对应UI
  final Widget Function(int section, int row, E object) itemBuilder;

  ///键盘事件
  final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;

  const KqSectionListView({
    Key? key,
    this.indexList,
    this.indexHeight,
    this.indexWidth,
    this.indexFont,
    this.sectionHeight,
    this.indexTextColor = KqThemeColors.text8C,
    this.isShowIndex = false,
    required this.section,
    this.isSameHeight = false,
    this.rowHeight,
    this.indexListHeight,
    this.isFixTop = false,
    required this.headerBuilder,
    this.footerBuilder,
    required this.itemBuilder,
    required this.itemList,
    this.listHeaderBuilder,
    this.listFooterBuilder,
    this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
  }) : super(key: key);
  @override
  State<KqSectionListView> createState() => _KqSectionListViewState<E>();
}

class _KqSectionListViewState<E> extends State<KqSectionListView<E>> {
  final GlobalKey listKey = GlobalKey(debugLabel: 'ListViewKey');
  final GlobalKey lastBoxKey = GlobalKey(debugLabel: 'LastBoxKey');
  List<Widget> slivers = [];
  ListService service = Get.put<ListService>(ListService());
  ScrollController scroll = ScrollController();

  ///各个分区头部的Y点数组
  List offsetHeadList = [];

  ///自定义高度分区的globalKey数组
  List<GlobalKey> sectionKeyList = [];

  ///最后一页的顶部位置
  double lastOffset = 0;

  ///最后一页顶部的index
  int lastIndex = 0;

  ///是否是点击触发
  bool isDidClick = false;

  ///索引的高宽
  double indexH = 0;
  double indexW = 0;

  ///索引提示窗
  late OverlayEntry entry;

  @override
  void initState() {
    super.initState();
    service.nowSection = 0;
    scroll.addListener(() {
      computeIndexOffset();
      setScrollAnimation(false);
    });

    ///索引弹窗
    if (widget.isShowIndex) {
      entry = OverlayEntry(
        builder: (context) {
          return Container(
            alignment: Alignment.center,
            child: GetBuilder(
              init: service,
              builder: (controller) => Container(
                alignment: Alignment.center,
                height: 32.r,
                width: 32.r,
                decoration: BoxDecoration(
                    color: KqThemeColors.bgBlack50,
                    borderRadius: BorderRadius.all(Radius.circular(4.r))),
                child: Text(
                  widget.indexList!.isNotEmpty
                      ? widget.indexList![service.didSection]
                      : "",
                  style:
                      TextStyle(fontSize: 16.sp, color: KqThemeColors.bgWhite),
                ),
              ),
            ),
          );
        },
      );
    }
  }

  setScrollAnimation(bool isEnd) {
    if (widget.isShowIndex) {
      for (int i = 0; i < offsetHeadList.length - 1; i++) {
        double sectionNowY = offsetHeadList[i];
        double sectionLastY = offsetHeadList[i + 1];
        if (scroll.offset > sectionNowY && scroll.offset < sectionLastY) {
          if (!isDidClick) {
            service.nowSection = i;
            service.update();
          }
          break;
        } else {
          continue;
        }
      }
      if (isEnd) {
        if (isDidClick) {
          service.nowSection = service.didSection;
          isDidClick = false;
        }
      }
    }
  }

  ///索引区
  Widget _buildListIndexView() {
    return Container(
      width: indexW + 12.r,
      alignment: Alignment.centerRight,
      child: GestureDetector(
        onTapDown: (details) {
          computeIndexOffset();
          double indexDouble = details.localPosition.dy / indexH;
          int index = indexDouble.truncate();
          if (!entry.mounted) {
            Overlay.of(context).insert(entry);
          }
          service.didSection = service.nowSection = index;
          double nowYOffset = offsetHeadList[index];
          service.nowSection = nowYOffset < lastOffset ? index : lastIndex;
          isDidClick = true;
          indexClickToScroll(nowYOffset);
        },
        onVerticalDragUpdate: (details) {
          computeIndexOffset();
          double indexDouble = details.localPosition.dy / indexH;
          int index = indexDouble.truncate();
          if (!entry.mounted) {
            Overlay.of(context).insert(entry);
          }
          if (index >= widget.section) {
            index = widget.section - 1;
          } else if (indexDouble < 0) {
            index = 0;
          } else {
            index = index;
          }
          service.didSection = index;
          if (service.nowSection != index) {
            service.nowSection = index < offsetHeadList.length - 1
                ? index
                : offsetHeadList.length - 1;
            double nowOffset = offsetHeadList[index];
            scroll.jumpTo(nowOffset < lastOffset
                ? offsetHeadList[index]
                : lastOffset > 0
                    ? lastOffset
                    : 0);
            service.update();
          }
        },
        onVerticalDragEnd: (details) {
          Future.delayed(const Duration(milliseconds: 500)).then((value) {
            if (entry.mounted) {
              entry.remove();
            }
          });
        },
        onTapUp: (details) {
          Future.delayed(const Duration(milliseconds: 500)).then((value) {
            if (entry.mounted) {
              entry.remove();
            }
          });
        },
        child: Container(
          padding: EdgeInsets.only(right: 12.r),
          height: widget.indexListHeight,
          child: GetBuilder(
            init: service,
            builder: (controller) => ListView.builder(
              itemCount:
                  widget.indexList != null ? widget.indexList!.length : 0,
              itemExtent: indexH,
              physics: const NeverScrollableScrollPhysics(),
              shrinkWrap: true,
              itemBuilder: ((context, index) {
                return Container(
                  alignment: Alignment.center,
                  width: indexW,
                  decoration: BoxDecoration(
                    color: (isDidClick
                            ? index == service.didSection
                            : index == service.nowSection)
                        ? KqThemeColors.textLightBlue
                        : KqThemeColors.bgTransparent,
                    borderRadius: BorderRadius.all(Radius.circular(indexH / 2)),
                  ),
                  child: Text(
                    widget.indexList!.isNotEmpty
                        ? widget.indexList![index]
                        : "",
                    style: TextStyle(
                        fontSize: widget.indexFont ?? 12.sp,
                        color: (isDidClick
                                ? index == service.didSection
                                : index == service.nowSection)
                            ? KqThemeColors.bgWhite
                            : widget.indexTextColor),
                  ),
                );
              }),
            ),
          ),
        ),
      ),
    );
  }

  ///索引栏操作后滚动事件
  indexClickToScroll(double nowY) {
    scroll.jumpTo(nowY < lastOffset
        ? nowY
        : lastOffset > 0
            ? lastOffset
            : 0);
    service.update();
  }

  @override
  Widget build(BuildContext context) {
    return _buildBody();
  }

  ///初始化内容
  Widget _buildBody() {
    return Stack(
      alignment: Alignment.topRight,
      key: listKey,
      children: [
        NotificationListener(
          onNotification: (ScrollNotification notification) {
            if (notification is ScrollEndNotification) {
              setScrollAnimation(true);
              return false;
            }
            return false;
          },
          child: CustomScrollView(
            controller: scroll,
            keyboardDismissBehavior: widget.keyboardDismissBehavior,
            slivers: getSlivers(),
          ),
        ),
        if (widget.isShowIndex) _buildListIndexView(),
      ],
    );
  }

  ///listView头部区域
  Widget _tableViewHeaderView(Widget child) {
    return SliverToBoxAdapter(
      child: child,
    );
  }

  ///listView低部区域
  Widget _tableViewFooterView(Widget child) {
    return SliverToBoxAdapter(
      child: child,
    );
  }

  ///非吸顶Section头部区域布局
  Widget _buildHeader({
    required int section,
  }) {
    final GlobalKey sectionKey = GlobalKey();
    Widget build = SizedBox(
      key: sectionKey,
      child: widget.headerBuilder(section),
    );
    sectionKeyList.add(sectionKey);
    return SliverToBoxAdapter(
      child: build,
    );
  }

  ///section底部区域布局
  Widget _buildFooter(Widget child) {
    return SliverToBoxAdapter(
      child: child,
    );
  }

  ///内容样式
  Widget _buildSliverList({
    required int section,
    required double height,
    required List<E> list,
  }) {
    if (widget.isSameHeight) {
      return SliverFixedExtentList(
          delegate: SliverChildBuilderDelegate(
              (_, int index) => widget.itemBuilder(section, index, list[index]),
              childCount: list.length),
          itemExtent: height);
    } else {
      return SliverList(
        delegate: SliverChildBuilderDelegate(
            (_, int index) => widget.itemBuilder(section, index, list[index]),
            childCount: list.length),
      );
    }
  }

  ///吸顶样式
  Widget _tableViewToFisTop({
    required int section,
    required double height,
    required List<E> list,
  }) {
    final GlobalKey sectionKey = GlobalKey();
    Widget build = SizedBox(
      key: sectionKey,
      child: widget.headerBuilder(section),
    );
    sectionKeyList.add(sectionKey);
    return SliverMainAxisGroup(slivers: [
      SliverHeader.builder(
        pinned: true,
        childBuilder: (context, shrinkOffset, overlapsContent) {
          return widget.sectionHeight == null
              ? build
              : Container(
                  constraints: BoxConstraints(
                      minHeight: widget.sectionHeight!,
                      maxHeight: widget.sectionHeight!),
                  child: build,
                );
        },
      ),
      _buildSliverList(section: section, list: list, height: height),
    ]);
  }

  List<Widget> getSlivers() {
    slivers = [];
    offsetHeadList = [];
    sectionKeyList = [];
    service.nowSection = 0;
    indexH = widget.indexHeight ?? 16.r;
    indexW = widget.indexWidth ?? 16.r;
    if (widget.listHeaderBuilder != null) {
      if (widget.listHeaderBuilder!() != null) {
        slivers.add(_tableViewHeaderView(widget.listHeaderBuilder!()!));
      }
    }
    for (int i = 0; i < widget.section; i++) {
      List<E> rowList = widget.itemList(i);
      double rowHeight = 36.r;
      if (widget.rowHeight != null) {
        rowHeight = widget.rowHeight!(i);
      }
      if (widget.isFixTop) {
        slivers.add(_tableViewToFisTop(
            section: i,
            height: rowHeight,
            list: rowList.whereType<E>().toList()));
      } else {
        slivers.add(_buildHeader(
          section: i,
        ));
        slivers.add(_buildSliverList(
            section: i,
            height: rowHeight,
            list: rowList.whereType<E>().toList()));
      }
      if (widget.footerBuilder != null) {
        if (widget.footerBuilder!(i) != null) {
          slivers.add(_buildFooter(widget.footerBuilder!(i)!));
        }
      }
    }
    if (widget.listFooterBuilder != null) {
      if (widget.listFooterBuilder!() != null) {
        slivers.add(_tableViewFooterView(widget.listFooterBuilder!()!));
      }
    }

    ///增加最后一个空分区用以定位总长度
    slivers.add(SliverToBoxAdapter(child: Container(key: lastBoxKey)));
    return slivers;
  }

  //计算索引位置
  void computeIndexOffset() {
    if (offsetHeadList.isEmpty) {
      double topHeight = 0;
      for (var i = 0; i < sectionKeyList.length; i++) {
        GlobalKey sectionKey = sectionKeyList[i];
        final RenderBox renderBox =
            sectionKey.currentContext!.findRenderObject() as RenderBox;
        final position = renderBox.globalToLocal(Offset.zero);
        if (i == 0) {
          topHeight = position.distance;
          offsetHeadList.add(0.0);
        } else {
          offsetHeadList.add(position.distance - topHeight);
        }
      }
      final RenderBox lastBox =
          lastBoxKey.currentContext!.findRenderObject() as RenderBox;
      final lastPosition = lastBox.globalToLocal(Offset.zero);
      offsetHeadList.add(lastPosition.distance - topHeight);

      ///计算最后一个顶部的索引，以及记录最后一页的Y坐标防止回弹
      double? myHeight = listKey.currentContext?.size!.height;
      lastOffset = offsetHeadList.last - myHeight;
      for (int j = widget.section; j >= 0; j--) {
        double yPoint = offsetHeadList[j];
        if (yPoint < lastOffset) {
          lastIndex = j;
          break;
        }
      }
    }
  }
}
